/*
 * Copyright (C) 2009-2012  Paulo Cesar Pereira de Andrade.
 *
 * This is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * Authors:
 *	Paulo Cesar Pereira de Andrade
 */

#ifndef _ethread_h
#define _ethread_h

#include "etypes.h"

#include <setjmp.h>
#include <signal.h>

#if HAVE_THREAD
#  define emutex_lock(mutex)						\
    do {								\
	if (pthread_mutex_lock(mutex))					\
	    eerror("pthread_mutex_lock: %s", strerror(errno));		\
    } while (0)

#  define emutex_unlock(mutex)						\
    do {								\
	if (pthread_mutex_unlock(mutex))				\
	    eerror("pthread_mutex_unlock: %s", strerror(errno));	\
    } while (0)

#  define emutex_init(mutex)						\
    do {								\
	if ((errno = pthread_mutex_init(mutex, null)))			\
	    eerror("pthread_mutex_init: %s", strerror(errno));		\
    } while (0)

#  define emutex_destroy(mutex)						\
    do {								\
	if ((errno = pthread_mutex_destroy(mutex)))			\
	    eerror("pthread_mutex_destroy: %s", strerror(errno));	\
    } while (0)

#  define ethreads_lock()	emutex_lock(&ethread_mutex)
#  define ethreads_unlock()	emutex_unlock(&ethread_mutex)

#  define ethread_kill(signo)						\
    do {								\
        pthread_kill(thread_self->pthread, signo);			\
    } while (0)

#else
#  define emutex_lock(mutex)	/**/
#  define emutex_unlock(mutex)	/**/
#  define emutex_init(mutex)	/**/
#  define emutex_destroy(mutex)	/**/
#  define ethreads_lock()	/**/
#  define ethreads_unlock()	/**/

#  define ethread_kill(signo)						\
    do {								\
        kill(getpid(), signo);						\
    } while (0)
#endif

/*
 * Types
 */
struct ethread {
    __cqq_struct	 qq;
    __mpc_struct	 cc;

    evector_t		*vec;

    struct {
	etype_t		 t;
	eword_t		 w;
	efloat_t	 d;
	ecdd_t		 dd;
    } ret;

#if HAVE_THREAD
    ethread_t		*next;
    pthread_t		 pthread;
#endif
};

#if HAVE_THREAD
/*
 * Prototypes
 */
extern void
init_thread(void);

extern void
finish_thread(void);

/*
 * Externs
 */
extern __thread ethread_t	*thread_self;
#else
#define thread_self		 thread_main
#endif

#endif /* _ethread_h */
